/*
 * @lc app=leetcode.cn id=106 lang=cpp
 *
 * [106] 从中序与后序遍历序列构造二叉树
 *
 * https://leetcode.cn/problems/construct-binary-tree-from-inorder-and-postorder-traversal/description/
 *
 * algorithms
 * Medium (72.41%)
 * Likes:    774
 * Dislikes: 0
 * Total Accepted:    205.9K
 * Total Submissions: 284.2K
 * Testcase Example:  '[9,3,15,20,7]\n[9,15,7,20,3]'
 *
 * 给定两个整数数组 inorder 和 postorder ，其中 inorder 是二叉树的中序遍历， postorder
 * 是同一棵树的后序遍历，请你构造并返回这颗 二叉树 。
 *
 *
 *
 * 示例 1:
 *
 *
 * 输入：inorder = [9,3,15,20,7], postorder = [9,15,7,20,3]
 * 输出：[3,9,20,null,null,15,7]
 *
 *
 * 示例 2:
 *
 *
 * 输入：inorder = [-1], postorder = [-1]
 * 输出：[-1]
 *
 *
 *
 *
 * 提示:
 *
 *
 * 1 <= inorder.length <= 3000
 * postorder.length == inorder.length
 * -3000 <= inorder[i], postorder[i] <= 3000
 * inorder 和 postorder 都由 不同 的值组成
 * postorder 中每一个值都在 inorder 中
 * inorder 保证是树的中序遍历
 * postorder 保证是树的后序遍历
 *
 *
 */

// @lc code=start
#include <algorithm>
#include <iostream>
#include <unordered_map>
#include <vector>
using namespace std;
// Definition for a binary tree node.
struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode() : val(0), left(nullptr), right(nullptr) {}
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
    TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
};

class Solution {
private:
    unordered_map<int, int> hash;

public:
    TreeNode *buildTree(vector<int> &inorder, vector<int> &postorder) {
        int n = inorder.size();
        reverse(postorder.begin(), postorder.end());
        for (int i = 0; i < n; ++i) {
            hash[inorder[i]] = i;
        }
        return helper(postorder, 0, n - 1, 0, n - 1);
    }

    TreeNode *helper(vector<int> &postorder, int post_left, int post_right, int in_left, int in_right) {
        if (post_left > post_right) {
            return nullptr;
        }
        int post_root = post_left;
        int in_root = hash[postorder[post_root]];
        TreeNode *root = new TreeNode(postorder[post_root]);
        int left_size = in_root - in_left;
        root->left = helper(postorder, post_right - left_size + 1, post_right, in_left, in_root - 1);
        root->right = helper(postorder, post_root + 1, post_right - left_size, in_root + 1, in_right);
        return root;
    }
};
// @lc code=end
